package com.robertux.leaderboard.servlets;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.robertux.leaderboard.beans.EstadoEntidad;
import com.robertux.leaderboard.beans.JsonResponse;
import com.robertux.leaderboard.beans.RolUsuario;
import com.robertux.leaderboard.beans.entities.Rol;
import com.robertux.leaderboard.beans.entities.SucursalSupervision;
import com.robertux.leaderboard.beans.entities.Usuario;
import com.robertux.leaderboard.beans.entities.external.Sucursal;
import com.robertux.leaderboard.util.MethodExecutionSecurity;
import com.robertux.leaderboard.util.MethodParamsChecker;
import com.robertux.leaderboard.util.gestoresModelos.GestorSucursales;
import com.robertux.leaderboard.util.gestoresModelos.GestorUsuarios;

@WebServlet("/AdminServlet/*")
public class AdminServlet extends BaseServlet {
	private static final long serialVersionUID = 1L;
	private GestorUsuarios gestor = new GestorUsuarios();
	private GestorSucursales gSucs = new GestorSucursales();
	private Logger logger;
       
    public AdminServlet() {
        super();
        this.logger = Logger.getLogger(this.getClass());
    }
    
    @MethodExecutionSecurity(requireAuthentication=false, roleLevelAllowed=RolUsuario.USUARIO)
    @MethodParamsChecker(requiredParams={"user", "password"})
    public JsonResponse login(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	if(this.gestor.validarUsuario(req.getParameter("user"), req.getParameter("password"))) {
    		Usuario usr = this.gestor.getUsuario(req.getParameter("user"));
    		
    		if(!usr.getEstado().equals(EstadoEntidad.ACTIVO.getCodigo())) {
    			return JsonResponse.fromError(1015);
    		}
    		
    		usr.setUltimoLogin(new Date());
    		this.gestor.actualizarUsuario(usr);
    		req.getSession().setAttribute(BaseServlet.USR_SESSION_NAME, usr);
    		return new JsonResponse();
    	} else {
    		return JsonResponse.fromError(1006);
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.USUARIO)
    public JsonResponse logout(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	req.getSession().removeAttribute(BaseServlet.USR_SESSION_NAME);
    	return new JsonResponse();
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.USUARIO)
    public JsonResponse checkUser(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Object objUsr;
    	if((objUsr = req.getSession().getAttribute(BaseServlet.USR_SESSION_NAME)) != null && objUsr instanceof Usuario) {
    		Usuario usr = (Usuario)objUsr;
    		
    		JsonObject obj = new JsonObject();
    		obj.addProperty("id", usr.getId());
    		obj.addProperty("name", usr.getUsuario());
    		obj.addProperty("role", usr.getRol().getNombre());
    		obj.addProperty("level", usr.getRol().getNivel());
    		return new JsonResponse(0, "OK", "user", obj);
    	} else {
    		return JsonResponse.fromError(1001);
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.USUARIO)
    @MethodParamsChecker(requiredParams={"userId", "currentPassword", "newPassword", "newPassword2"})
    public JsonResponse changePassword(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	if(!req.getParameter("newPassword").trim().equals(req.getParameter("newPassword2").trim())) {
    		return JsonResponse.fromError(1011);
    	}
    	
    	Usuario usr = this.gestor.getUsuario(Integer.parseInt(req.getParameter("userId")));
    	
    	if(!this.gestor.validarClaveUsuario(usr, req.getParameter("currentPassword"))) {
    		return JsonResponse.fromError(1012);
    	}
    	
    	if(this.gestor.cambiarClaveUsuario(usr, req.getParameter("currentPassword"), req.getParameter("newPassword"))) {
    		return new JsonResponse(0, "Clave cambiada satisfactoriamente");
    	} else {
    		return JsonResponse.fromError(1013, usr.getNombre());
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"page", "rowsPerPage", "filter"})
    public JsonResponse getUsers(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonArray arr = new JsonArray();
    	List<Usuario> usrs;
    	long totalUsuarios = 0;
    	if(req.getParameter("branchId") != null && Integer.parseInt(req.getParameter("branchId")) > 0) {
    		usrs = this.gestor.getUsuarios(Integer.parseInt(req.getParameter("branchId")), Integer.parseInt(req.getParameter("page")), Integer.parseInt(req.getParameter("rowsPerPage")), req.getParameter("filter"));
    		totalUsuarios = this.gestor.getTotalUsuarios(Integer.parseInt(req.getParameter("branchId")), req.getParameter("filter"));
    	} else {
    		usrs = this.gestor.getUsuarios(Integer.parseInt(req.getParameter("page")), Integer.parseInt(req.getParameter("rowsPerPage")), req.getParameter("filter"));
    		totalUsuarios = this.gestor.getTotalUsuarios(req.getParameter("filter"));
    	}
    	for(Usuario usr: usrs) {
    		Sucursal suc = this.gSucs.getSucursal(usr.getSucursalId());
    		JsonObject obj = new JsonObject();
    		obj.addProperty("id", usr.getId());
    		obj.addProperty("usuario", usr.getUsuario());
    		obj.addProperty("nombre", usr.getNombre());
    		obj.addProperty("estado", EstadoEntidad.fromCodigo(usr.getEstado()).toString());
    		obj.addProperty("rol", usr.getRol().getNombre());
    		obj.addProperty("nivelRol", usr.getRol().getNivel());
    		obj.addProperty("idEmpleado", usr.getEmpleadoId());
    		obj.addProperty("idVendedor", usr.getVendedorId());
    		obj.addProperty("idSucursal", usr.getSucursalId());
    		obj.addProperty("nombreSucursal", (suc != null? suc.getNombre(): "(ninguna)"));
    		obj.addProperty("cantSucursales", usr.getSucursalesSupervision().size());
    		obj.addProperty("ultAcceso", usr.getUltimoLogin() != null? new SimpleDateFormat("dd/MM/yyyy hh:mm:ss aaa").format(usr.getUltimoLogin()): "");
    		arr.add(obj);
    	}
    	
    	JsonResponse jsonResp = new JsonResponse(0, "OK", "users", arr);
    	jsonResp.add("total", new JsonPrimitive(totalUsuarios));
    	return jsonResp;
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.EVALUADOR)
    public JsonResponse getUserNames(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonArray arr = new JsonArray();
    	for(Usuario usr: this.gestor.getUsuarios()) {
    		if(!usr.getEstado().equals(EstadoEntidad.ELIMINADO.getCodigo())) {
    			arr.add(new JsonPrimitive(usr.getUsuario() + " - " + usr.getNombre()));
    		}
    	}
    	
    	return new JsonResponse(0, "OK", "userNames", arr);
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    public JsonResponse getRoles(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonArray arr = new JsonArray();
    	for(Rol rol: this.gestor.getRoles()) {
    		JsonObject obj = new JsonObject();
    		obj.addProperty("id", rol.getId());
    		obj.addProperty("nombre", rol.getNombre());
    		obj.addProperty("nivel", rol.getNivel());
    		arr.add(obj);
    	}
    	
    	return new JsonResponse(0, "OK", "roles", arr);
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.VENDEDOR)
    public JsonResponse getBranchesUser(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonArray arr = new JsonArray();
    	Object objUsr;
    	Usuario usr = null;
    	boolean showOwnedOnly = false;
    	
    	if(req.getParameter("userId") != null && req.getParameter("userId").trim().length() > 0) {
    		this.logger.debug("Obteniendo usuario con ID " + req.getParameter("userId"));
    		usr = this.gestor.getUsuario(Integer.parseInt(req.getParameter("userId")));
    		
    	} else if((objUsr = req.getSession().getAttribute(BaseServlet.USR_SESSION_NAME)) != null && objUsr instanceof Usuario) {
        	usr = (Usuario)objUsr;
        	
    	} else {
    		return JsonResponse.fromError(1001);
    	}
    	
    	if(req.getParameter("showOwnedOnly") != null && "S".equalsIgnoreCase(req.getParameter("showOwnedOnly"))) {
    		showOwnedOnly = true;
    	}
    	
    	Collections.sort(usr.getSucursalesSupervision());
    	RolUsuario rol = RolUsuario.fromNivel(usr.getRol().getNivel()); 
		List<Sucursal> sucursales = new ArrayList<Sucursal>((RolUsuario.SUPERVISOR.equals(rol) || RolUsuario.JEFE.equals(rol)) && showOwnedOnly? 
				this.gSucs.getSucursales(usr): 
				this.gSucs.getSucursales());
		
		Collections.sort(sucursales, new Comparator<Sucursal>() {
			@Override
			public int compare(Sucursal o1, Sucursal o2) {
				return o1.getNombre().compareTo(o2.getNombre());
			}
		});
		
		if(req.getParameter("showAllSelector") != null && "YES".equals(req.getParameter("showAllSelector"))) {
    		sucursales.add(new Sucursal(0, "TODAS"));
    	}
		
		for(Sucursal suc: sucursales) {
			if(suc != null) {
				JsonObject sucObj = new JsonObject();
	    		sucObj.addProperty("id", suc.getId());
	    		sucObj.addProperty("name", suc.getNombre());
	    		sucObj.addProperty("selected", usr.getSucursalesSupervision().contains(new SucursalSupervision(suc.getId())));
	    		arr.add(sucObj);
			}
		}
    	return new JsonResponse(0, "OK", "branches", arr);
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"user"})
    public JsonResponse getBranchUser(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonResponse jsonResp = new JsonResponse();
    	
    	if(req.getParameter("user").trim().length() > 0) {
	    	Usuario usr = this.gestor.getUsuario(req.getParameter("user"));
	    	if(usr != null) {
	    		Sucursal suc = this.gSucs.getSucursal(usr.getSucursalId());
	    		if(suc != null) {
	    			jsonResp.add("branch", new JsonPrimitive(suc.getNombre()));
	    		} else {
	    			jsonResp.add("branch", new JsonPrimitive("(ninguna)"));
	    		}
	    	} else {
	    		jsonResp = JsonResponse.fromError(1019, req.getParameter("user"));
	    	}
    	}
    	
    	return jsonResp;
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"user", "name", "roleId", "password", "repeatPassword", "empId", "sellerId", "branchId"})
    public JsonResponse addUser(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Usuario usrExistente = null;
    	if(!req.getParameter("password").trim().equals(req.getParameter("repeatPassword").trim())) {
    		return JsonResponse.fromError(1007);
    	}
    	
    	if((usrExistente = this.gestor.getUsuario(req.getParameter("user"))) != null
    			&& usrExistente.getEstado().equals(EstadoEntidad.ACTIVO.getCodigo())) {
    		return JsonResponse.fromError(1008);
    	}
    	
    	Rol rol = this.gestor.getRol(Integer.parseInt(req.getParameter("roleId")));
    	if(rol == null) {
    		return JsonResponse.fromError(1009, req.getParameter("roleId"));
    	}
    	
    	Usuario usr = new Usuario(req.getParameter("name"), req.getParameter("user"), req.getParameter("password"), 
    			EstadoEntidad.ACTIVO.getCodigo(), req.getParameter("empId"), req.getParameter("sellerId"), Integer.parseInt(req.getParameter("branchId")));
    	
    	usr.setRol(rol);
    	
    	if(this.gestor.agregarUsuario(usr)) {
    		if(usr.getRol().getNivel() == 4 && req.getParameter("sucursalesAdm") != null && req.getParameter("sucursalesAdm").trim().length() > 0) {
    	    	for(String suc: req.getParameter("sucursalesAdm").split(",")) {
    	    		this.logger.debug("Agregando sucursal con Id " + suc);
    				usr.addSucursalSupervision(new SucursalSupervision(Integer.parseInt(suc.trim())));
    			}
    	    	this.gestor.actualizarUsuario(usr);
        	}
    		return new JsonResponse(0, "Usuario agregado satisfactoriamente al sistema");
    	} else {
    		return JsonResponse.fromError(1010);
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"userId", "state"})
    public JsonResponse changeUserState(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Usuario usr = this.gestor.getUsuario(Integer.parseInt(req.getParameter("userId")));
    	EstadoEntidad estado = EstadoEntidad.fromCodigo(req.getParameter("state"));
    	usr.setEstado(estado.getCodigo());
    	
    	if(this.gestor.actualizarUsuario(usr)) {
    		return new JsonResponse(0, estado.equals(EstadoEntidad.ACTIVO)? "Usuario activado satisfactoriamente": "Usuario desactivado satisfactoriamente");
    	} else {
    		return JsonResponse.fromError(1016, req.getParameter("userId"));
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"userId", "name", "roleId", "empId", "sellerId", "branchId"})
    public JsonResponse updateUser(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	Usuario usr = this.gestor.getUsuario(Integer.parseInt(req.getParameter("userId")));
    	
    	if(req.getParameter("password").trim().length() > 0 &&
    			!req.getParameter("password").trim().equals(req.getParameter("repeatPassword").trim())) {
    		return JsonResponse.fromError(1007);
    	}
    	
    	Rol rol = this.gestor.getRol(Integer.parseInt(req.getParameter("roleId")));
    	if(rol == null) {
    		return JsonResponse.fromError(1009, req.getParameter("roleId"));
    	}
    	usr.setRol(rol);
    	
    	if(req.getParameter("password").trim().length() > 0) {
    		if(!this.gestor.cambiarClaveUsuario(usr, req.getParameter("password"))) {
    			return JsonResponse.fromError(1013, req.getParameter("userId"));
    		}
    	}
    	
    	if(usr.getRol().getNivel() == 4 && req.getParameter("sucursalesAdm") != null && req.getParameter("sucursalesAdm").trim().length() > 0) {
    		for(SucursalSupervision suc: usr.getSucursalesSupervision()) {
    			this.gestor.eliminarSucursalUsuario(suc);
    			//usr.removeSucursalSupervision(suc);
    		}
    		usr.getSucursalesSupervision().clear();
    		this.gestor.actualizarUsuario(usr);
	    	for(String suc: req.getParameter("sucursalesAdm").split(",")) {
				usr.addSucursalSupervision(new SucursalSupervision(Integer.parseInt(suc.trim())));
			}
    	}
    	
    	usr.setNombre(req.getParameter("name"));
    	usr.setEmpleadoId(req.getParameter("empId"));
    	usr.setVendedorId(req.getParameter("sellerId"));
    	usr.setSucursalId(Integer.parseInt(req.getParameter("branchId")));
    	if(this.gestor.actualizarUsuario(usr)) {
    		return new JsonResponse(0, "Usuario actualizado satisfactoriamente");
    	} else {
    		return JsonResponse.fromError(1034, req.getParameter("userId"));
    	}
    }

    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.SUPERVISOR)
    @MethodParamsChecker(requiredParams={"userId"})
    public JsonResponse delUser(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	if(this.gestor.eliminarUsuario(this.gestor.getUsuario(Integer.parseInt(req.getParameter("userId"))))) {
    		return new JsonResponse(0, "Usuario eliminado satisfactoriamente");
    	} else {
    		return JsonResponse.fromError(1014, req.getParameter("userId"));
    	}
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.VENDEDOR)
    public JsonResponse getBranches(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonArray jsSucursales = new JsonArray();
    	
    	Object objUsr;
    	Usuario usr = null;
    	
    	if((objUsr = req.getSession().getAttribute(BaseServlet.USR_SESSION_NAME)) != null && objUsr instanceof Usuario) {
        	usr = (Usuario)objUsr;
    	} else {
    		return JsonResponse.fromError(1001);
    	}
    	
    	RolUsuario rol = RolUsuario.fromNivel(usr.getRol().getNivel()); 
    	if(RolUsuario.SUPERVISOR.equals(rol) || RolUsuario.JEFE.equals(rol)) {
    		JsonResponse jsonResp = this.getBranchesUser(req, resp);
    		JsonArray branches = (JsonArray)jsonResp.getJsonObject().get("branches"); 
    		for(int i=0; i<branches.size(); i++) {
    			if(((JsonObject)branches.get(i)).get("id").getAsInt() > 0)
    			jsSucursales.add(branches.get(i));
    		}
    	} else {
	    	jsSucursales.addAll(this.gSucs.getJsSucursales());
	    	if(req.getParameter("showAllSelector") != null && "YES".equals(req.getParameter("showAllSelector"))) {
	    		JsonObject sucObj = new JsonObject();
	    		sucObj.addProperty("id", 0);
	    		sucObj.addProperty("name", "TODAS");
	    		sucObj.addProperty("selected", false);
	    		jsSucursales.add(sucObj);
	    	}
    	}
    	
    	return new JsonResponse(0, "OK", "branches", jsSucursales);
    }
    
    @MethodExecutionSecurity(requireAuthentication=true, roleLevelAllowed=RolUsuario.GERENTE)
    public JsonResponse getSupervisores(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    	JsonResponse jsonResp = new JsonResponse();
    	JsonArray arr = new JsonArray();
    	
    	List<Usuario> sups = this.gestor.getUsuarios(RolUsuario.SUPERVISOR);
    	for(Usuario sup: sups) {
    		JsonObject obj = new JsonObject();
    		obj.addProperty("id", sup.getId());
    		obj.addProperty("user", sup.getUsuario());
    		obj.addProperty("name", sup.getNombre());
    		arr.add(obj);
    	}
    	
    	if(req.getParameter("showAllSelector") != null && "YES".equals(req.getParameter("showAllSelector"))) {
    		JsonObject obj = new JsonObject();
    		obj.addProperty("id", 0);
    		obj.addProperty("user", "TODOS");
    		obj.addProperty("name", "TODOS");
    		arr.add(obj);
    	}
    	
    	jsonResp.add("supervisores", arr);
    	return jsonResp;
    }
    
    @MethodExecutionSecurity(requireAuthentication=false, roleLevelAllowed=RolUsuario.USUARIO)
    @MethodParamsChecker(requiredParams={"errCode"})
    public JsonResponse checkErrCode(HttpServletRequest req, HttpServletResponse resp) {
    	return JsonResponse.fromError(Integer.parseInt(req.getParameter("errCode")));
    }
}
